home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / nos042_s / icmpcmd.c < prev    next >
C/C++ Source or Header  |  1994-09-16  |  7KB  |  287 lines

  1. /* ICMP-related user commands
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4.  
  5. /****************************************************************************
  6. *    $Id: icmpcmd.c 1.2 93/07/16 11:45:26 ROOT_DOS Exp $
  7. *    14 Jun 93    1.2        GT    Fix warnings.                                    *
  8. *
  9. *  ATARI Version by David Nash - dnash@chaos.demon.co.uk
  10. *
  11. *  __stdargs declared for pingtx, doping
  12. ****************************************************************************/
  13.  
  14. #include <stdio.h>
  15. #include "global.h"
  16. #include "icmp.h"
  17. #include "ip.h"
  18. #include "mbuf.h"
  19. #include "netuser.h"
  20. #include "internet.h"
  21. #include "timer.h"
  22. #include "socket.h"
  23. #include "proc.h"
  24. #include "session.h"
  25. #include "cmdparse.h"
  26. #include "commands.h"
  27.  
  28. static int doicmpec __ARGS((int argc, char *argv[],void *p));
  29. static int doicmpstat __ARGS((int argc, char *argv[],void *p));
  30. static int doicmptr __ARGS((int argc, char *argv[],void *p));
  31. static void __stdargs pingtx __ARGS((int s,void *ping1,void *p));
  32. static void pinghdr __ARGS((struct session *sp,struct ping *ping));
  33.  
  34. static struct cmds Icmpcmds[] = {
  35.     { "echo",        doicmpec,    0, 0, NULLCHAR},
  36.     { "status",    doicmpstat,    0, 0, NULLCHAR},
  37.     {"trace",    doicmptr,    0, 0, NULLCHAR},
  38.     { NULLCHAR}
  39. };
  40.  
  41. int Icmp_trace;
  42. static int Icmp_echo = 1;
  43.  
  44. int
  45. doicmp(argc,argv,p)
  46. int argc;
  47. char *argv[];
  48. void *p;
  49. {
  50.     return subcmd(Icmpcmds,argc,argv,p);
  51. }
  52.  
  53. static int
  54. doicmpstat(argc,argv,p)
  55. int argc;
  56. char *argv[];
  57. void *p;
  58. {
  59.     register int i;
  60.     int lim;
  61.  
  62.     /* Note that the ICMP variables are shown in column order, because
  63.      * that lines up the In and Out variables on the same line
  64.      */
  65.     lim = NUMICMPMIB/2;
  66.     for(i=1;i<=lim;i++){
  67.         tprintf("(%2u)%-20s%10lu",i,Icmp_mib[i].name,
  68.          Icmp_mib[i].value.integer);
  69.         tprintf("     (%2u)%-20s%10lu\n",i+lim,Icmp_mib[i+lim].name,
  70.          Icmp_mib[i+lim].value.integer);
  71.     }
  72.     return 0;
  73. }
  74. static int
  75. doicmptr(argc,argv,p)
  76. int argc;
  77. char *argv[];
  78. void *p;
  79. {
  80.     return setbool(&Icmp_trace,"ICMP tracing",argc,argv);
  81. }
  82. static int
  83. doicmpec(argc,argv,p)
  84. int argc;
  85. char *argv[];
  86. void *p;
  87. {
  88.     return setbool(&Icmp_echo,"ICMP echo response accept",argc,argv);
  89. }
  90.  
  91. /* Send ICMP Echo Request packets */
  92. int
  93. __stdargs doping(argc,argv,p)
  94. int argc;
  95. char *argv[];
  96. void *p;
  97. {
  98.     struct proc *pinger = NULLPROC;    /* Transmit process */
  99.     struct sockaddr_in from;
  100.     struct icmp icmp;
  101.     struct mbuf *bp;
  102.     int32 timestamp,rtt,abserr;
  103.     int s,fromlen;
  104.     struct ping ping;
  105.     struct session *sp;
  106.  
  107.     memset((char *)&ping,0,sizeof(ping));
  108.     /* Allocate a session descriptor */
  109.     if((sp = ping.sp = newsession(argv[1],PING)) == NULLSESSION){
  110.         tprintf("Too many sessions\n");
  111.         return 1;
  112.     }
  113.     if((sp->s = s = socket(AF_INET,SOCK_RAW,ICMP_PTCL)) == -1){
  114.         tprintf("Can't create socket\n");
  115.         keywait(NULLCHAR,1);
  116.         freesession(sp);
  117.         return 1;
  118.     }
  119.     tprintf("Resolving %s... ",sp->name);
  120.     if((ping.target = resolve(sp->name)) == 0){
  121.         tprintf("Host %s unknown\n",sp->name);
  122.         keywait(NULLCHAR,1);
  123.         freesession(sp);
  124.         return 1;
  125.     }
  126.     if(argc > 2)
  127.         ping.len = atoi(argv[2]);
  128.  
  129.     if(argc > 3)
  130.         ping.interval = atol(argv[3]);
  131.  
  132.  
  133.     /* Optionally ping a range of IP addresses */
  134.     if(argc > 4)
  135.         ping.incflag = 1;
  136.  
  137.     if(ping.interval != 0){
  138.         pinger = newproc("pingtx",300,pingtx,s,&ping,NULL,0);
  139.     } else {
  140.         /* One shot ping; let echo_proc hook handle response.
  141.          * An ID of MAXINT16 will not be confused with a legal socket
  142.          * number, which is used to identify repeated pings
  143.          */
  144.         pingem(s,ping.target,0,MAXINT16,ping.len);
  145.         freesession(sp);
  146.         return 0;
  147.     }
  148.     /* Now collect the replies */
  149.     pinghdr(sp,&ping);
  150.     for(;;){
  151.         fromlen = sizeof(from);
  152.         if(recv_mbuf(s,&bp,0,(char *)&from,&fromlen) == -1)
  153.             break;
  154.         ntohicmp(&icmp,&bp);
  155.         if(icmp.type != ICMP_ECHO_REPLY || icmp.args.echo.id != s){
  156.             /* Ignore other people's responses */
  157.             free_p(bp);
  158.             continue;
  159.         }
  160.         /* Get stamp */
  161.         if(pullup(&bp,(char *)×tamp,sizeof(timestamp))
  162.          != sizeof(timestamp)){
  163.             /* The timestamp is missing! */
  164.             free_p(bp);    /* Probably not necessary */
  165.             continue;
  166.         }
  167.         free_p(bp);
  168.  
  169.         ping.responses++;
  170.  
  171.         /* Compute round trip time, update smoothed estimates */
  172.         rtt = msclock() - timestamp;
  173.         abserr = (rtt > ping.srtt) ? (rtt-ping.srtt) : (ping.srtt-rtt);
  174.  
  175.         if(ping.responses == 1){
  176.             /* First response, base entire SRTT on it */
  177.             ping.srtt = rtt;
  178.             ping.mdev = 0;
  179.         } else {
  180.             ping.srtt = (7*ping.srtt + rtt + 4) >> 3;
  181.             ping.mdev = (3*ping.mdev + abserr + 2) >> 2;
  182.         }
  183.         if((ping.responses % 20) == 0)
  184.             pinghdr(sp,&ping);
  185.         tprintf("%10lu%10lu%5lu%10lu%10lu%10lu\n",
  186.          ping.sent,ping.responses,
  187.          (ping.responses*100 + ping.sent/2)/ping.sent,
  188.          rtt,ping.srtt,ping.mdev);
  189.     }
  190.     if(pinger != NULLPROC)
  191.         killproc(pinger);
  192.     freesession(sp);
  193.     return 0;
  194. }
  195. static void
  196. pinghdr(sp,ping)
  197. struct session *sp;
  198. struct ping *ping;
  199. {
  200.     tprintf("Pinging %s (%s); data %d interval %lu ms:\n",
  201.      sp->name,inet_ntoa(ping->target),ping->len,ping->interval);
  202.     tprintf("      sent      rcvd    %       rtt   avg rtt      mdev\n");
  203. }
  204.  
  205. void
  206. echo_proc(source,dest,icmp,bp)
  207. int32 source;
  208. int32 dest;
  209. struct icmp *icmp;
  210. struct mbuf *bp;
  211. {
  212.     int32 timestamp,rtt;
  213.  
  214.     if(Icmp_echo && icmp->args.echo.id == MAXINT16
  215.      && pullup(&bp,(char *)×tamp,sizeof(timestamp))
  216.      == sizeof(timestamp)){
  217.         /* Compute round trip time */
  218.         rtt = msclock() - timestamp;
  219.         tprintf("%s: rtt %lu\n",inet_ntoa(source),rtt);
  220.     }
  221.     free_p(bp);
  222. }
  223. /* Ping transmit process. Runs until killed */
  224. static void __stdargs
  225. pingtx(s,ping1,p)
  226. int s;        /* Socket to use */
  227. void *ping1;
  228. void *p;
  229. {
  230.     struct ping *ping;
  231.  
  232.     ping = (struct ping *)ping1;
  233.     ping->sent = 0;
  234.     if(ping->incflag){
  235.         for(;;){
  236.             pingem(s,ping->target++,0,MAXINT16,ping->len);
  237.             ping->sent++;
  238.             Pause(ping->interval);
  239.         }
  240.     } else {
  241.         for(;;){
  242.             pingem(s,ping->target,(int16)ping->sent++,(int16)s,ping->len);
  243.             Pause(ping->interval);
  244.         }
  245.     }
  246. }
  247.  
  248.  
  249. /* Send ICMP Echo Request packet */
  250. int pingem(
  251.     int s,            /* Raw socket on which to send ping */
  252.     int32 target,    /* Site to be pinged */
  253.     int16 seq,        /* ICMP Echo Request sequence number */
  254.     int16 id,        /* ICMP Echo Request ID */
  255.     int16 len)        /* Length of optional data field */
  256. {
  257.     struct mbuf *data;
  258.     struct mbuf *bp;
  259.     struct icmp icmp;
  260.     struct sockaddr_in to;
  261.     int32 clock;
  262.  
  263.     clock = msclock();
  264.     data = ambufw((int16)(len+sizeof(clock)));
  265.     data->cnt = len+sizeof(clock);
  266.     /* Set optional data field, if any, to all 55's */
  267.     if(len != 0)
  268.         memset(data->data+sizeof(clock),0x55,len);
  269.  
  270.     /* Insert timestamp and build ICMP header */
  271.     memcpy(data->data,(char *)&clock,sizeof(clock));
  272.     icmpOutEchos++;
  273.     icmpOutMsgs++;
  274.     icmp.type = ICMP_ECHO;
  275.     icmp.code = 0;
  276.     icmp.args.echo.seq = seq;
  277.     icmp.args.echo.id = id;
  278.     if((bp = htonicmp(&icmp,data)) == NULLBUF){
  279.         free_p(data);
  280.         return 0;
  281.     }
  282.     to.sin_family = AF_INET;
  283.     to.sin_addr.s_addr = target;
  284.     send_mbuf(s,bp,0,(char *)&to,sizeof(to));
  285.     return 0;
  286. }
  287.